<?php

namespace app\admin\controller\course;

use app\admin\controller\Api;
use app\common\controller\Backend;
use app\common\model\CourseSchedule;
use app\admin\model\Ocation;
use think\Db;
use think\Exception;
use think\exception\PDOException;
use think\exception\ValidateException;

/**
 * 课程排期管理
 *
 * @icon fa fa-calendar-check-o
 */
class Schedule extends Backend
{
    /**
     * CourseSchedule模型对象
     * @var \app\common\model\CourseSchedule
     */
    protected $model = null;

    protected $noNeedRight = ['clear', 'getSubjectList', 'getCommunityList', 'export', 'generate', 'confirmSchedule', 'checkFormalSchedule', 'cancelSchedule'];
    protected $noNeedLogin = ['clear', 'getSubjectList', 'getCommunityList', 'export', 'generate', 'confirmSchedule', 'checkFormalSchedule', 'cancelSchedule'
    ];
    public $timeSlotDetails = [];

    /**
     * Redis缓存相关方法
     */

    /**
     * 生成缓存键
     */
    private function generateCacheKey($publicwelfare_id, $community_id = 0, $search = '')
    {
        $key = "schedule:list:{$publicwelfare_id}";
        if ($community_id > 0) {
            $key .= ":community:{$community_id}";
        }
        if (!empty($search)) {
            $key .= ":search:" . md5($search);
        }
        return $key;
    }

    /**
     * 获取Redis实例
     */
    private function getRedisInstance()
    {
        try {
            // 检查Redis扩展是否可用
            if (!class_exists('Redis')) {
                return false;
            }

            /** @var \Redis $redis */
            $redis = new \Redis();
            // 获取Redis配置
            $config = config('cache.redis');
            $host = $config['host'] ?? '127.0.0.1';
            $port = $config['port'] ?? 6379;
            $timeout = $config['timeout'] ?? 0;
            $password = $config['password'] ?? '';
            $select = $config['select'] ?? 0;

            // 连接Redis
            if (!$redis->connect($host, $port, $timeout)) {
                return false;
            }

            // 验证密码
            if (!empty($password) && !$redis->auth($password)) {
                $redis->close();
                return false;
            }

            // 选择数据库
            if ($select > 0) {
                $redis->select($select);
            }

            return $redis;
        } catch (\Exception $e) {
            // 记录错误日志
            file_put_contents($_SERVER["DOCUMENT_ROOT"]."/../runtime/log/redis_error.log",
                date('Y-m-d H:i:s') . " - Redis连接失败: " . $e->getMessage() . "\n", FILE_APPEND);
            return false;
        }
    }

    /**
     * 从Redis获取缓存数据
     */
    private function getCacheData($cacheKey)
    {
        try {
            // 检查是否需要跳过缓存
            $skipCache = $this->request->param('skip_cache', 0);
            if ($skipCache) {
                return false;
            }

            $redis = $this->getRedisInstance();
            if ($redis === false) {
                return false;
            }

            // 获取缓存数据
            $cachedData = $redis->get($cacheKey);
            $redis->close();

            if ($cachedData !== false) {
                return json_decode($cachedData, true);
            }

            return false;
        } catch (\Exception $e) {
            // 记录错误日志
            file_put_contents($_SERVER["DOCUMENT_ROOT"]."/../runtime/log/redis_error.log",
                date('Y-m-d H:i:s') . " - 获取缓存失败: " . $e->getMessage() . "\n", FILE_APPEND);
            return false;
        }
    }

    /**
     * 设置Redis缓存数据
     */
    private function setCacheData($cacheKey, $data, $expire = 3600)
    {
        try {
            $redis = $this->getRedisInstance();
            if ($redis === false) {
                return false;
            }

            // 设置缓存数据
            $result = $redis->setex($cacheKey, $expire, json_encode($data));
            $redis->close();

            return $result;
        } catch (\Exception $e) {
            // 记录错误日志
            file_put_contents($_SERVER["DOCUMENT_ROOT"]."/../runtime/log/redis_error.log",
                date('Y-m-d H:i:s') . " - 设置缓存失败: " . $e->getMessage() . "\n", FILE_APPEND);
            return false;
        }
    }

    /**
     * 清除指定publicwelfare_id的所有缓存
     */
    private function clearCacheByPublicwelfareId($publicwelfare_id)
    {
        try {
            $redis = $this->getRedisInstance();
            if ($redis === false) {
                return false;
            }

            // 清除该publicwelfare_id的所有缓存键
            $pattern = "schedule:list:{$publicwelfare_id}*";
            $keys = $redis->keys($pattern);

            if (!empty($keys)) {
                $redis->del($keys);
            }

            $redis->close();
            return true;
        } catch (\Exception $e) {
            // 记录错误日志
            file_put_contents($_SERVER["DOCUMENT_ROOT"]."/../runtime/log/redis_error.log",
                date('Y-m-d H:i:s') . " - 清除缓存失败: " . $e->getMessage() . "\n", FILE_APPEND);
            return false;
        }
    }

    public function _initialize()
    {
        parent::_initialize();
        $this->model = new \app\common\model\CourseSchedule;
        $this->view->assign("courseList", $this->model::getCourseList(1, 3));
        $this->view->assign("communityList", $this->model::getCommunityList(1, 3));
        $this->view->assign("timeZoneList", $this->model::getTimeZoneList(1, 3));
        $this->view->assign("timeSlotList", $this->model::getTimeSlotList(1, 3));
        $this->view->assign("monthList", $this->model::getMonthList(1, 3));
        $this->view->assign("statusList", ['0' => __('Disabled'), '1' => __('Normal')]);

        // 获取公益项目列表
        $publicwelfareList = Db::name('fa_community_publicwelfare')
            ->where('status', 1)
            ->field('id, project_name')
            ->select();
        $this->view->assign("publicwelfareList", $publicwelfareList);
    }

    /**
     * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
     * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
     * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
     */


    /**
     * 查看
     */
    public function index()
    {
        // 设置过滤方法
        $this->request->filter(['strip_tags', 'trim']);

        // 获取项目ID参数
        $publicwelfare_id = $this->request->get('publicwelfare_id', 0);
        $community_id = $this->request->get('community_id', 0);

        // 完全避免使用pathinfo函数，直接使用已知的控制器和方法名
        // 这样可以避免警告出现
        if ($this->request->isAjax()) {
            // 如果发送的来源是Selectpage，则转发到Selectpage
            if ($this->request->request('keyField')) {
                return $this->selectpage();
            }

            // 生成缓存键
            $search = $_REQUEST['search'] ?? '';
            $cacheKey = $this->generateCacheKey($publicwelfare_id, $community_id, $search);

            // 尝试从Redis获取缓存数据
            $cachedResult = $this->getCacheData($cacheKey);
            if ($cachedResult !== false) {
                return json($cachedResult);
            }

            list($where, $sort, $order, $offset, $limit) = $this->buildparams();

            // 只有当指定了具体项目id时，才添加过滤条件
            if ($publicwelfare_id > 0) {
                $this->model = $this->model->where('publicwelfare_id', $publicwelfare_id);
            }

            $query = $this->model
                ->where($where)
                ->order('year', 'asc')  // 先按年份
                ->order('month', 'asc')  // 再按月份
                ->order('day', 'asc')
                ->order('timeslot', 'asc');

            // 一次性获取所有数据（移除分页限制）
            // 修改: 直接使用select()获取数组，避免使用collection转换提高性能
            $list = $query->select();
            // 修改: 如果$list不是数组则转换为数组
            if (!is_array($list)) {
                $list = $list->toArray();
            }

            // 优化: 预先获取所有需要的文本映射，避免在循环中重复查询
            $timeSlotTexts = [];
            $communityTexts = [];
            $timeZoneTexts = [];
            $courseTexts = [];

            // 收集所有需要查询的code
            $timeSlotCodes = [];
            $communityCodes = [];
            $timeZoneCodes = [];
            $courseCodes = [];
            $publicwelfareIds = [];

            foreach ($list as $v) {
                $timeSlotCodes[] = $v['time_slot_code'];
                $communityCodes[] = $v['community_code'];
                $timeZoneCodes[] = $v['time_zone_code'];
                $courseCodes[] = $v['course_code'];
                $publicwelfareIds[] = $v['publicwelfare_id'];
            }

            // 去重
            $timeSlotCodes = array_unique($timeSlotCodes);
            $communityCodes = array_unique($communityCodes);
            $timeZoneCodes = array_unique($timeZoneCodes);
            $courseCodes = array_unique($courseCodes);
            $publicwelfareIds = array_unique($publicwelfareIds);

            // 预查询所有需要的文本映射
            foreach ($publicwelfareIds as $pwId) {
                foreach ($timeSlotCodes as $code) {
                    $timeSlotTexts["{$pwId}_{$code}"] = CourseSchedule::getTimeSlotText($pwId, $code);
                }
                foreach ($communityCodes as $code) {
                    $communityTexts["{$pwId}_{$code}"] = CourseSchedule::getCommunityText($pwId, $code);
                }
                foreach ($timeZoneCodes as $code) {
                    $timeZoneTexts["{$pwId}_{$code}"] = CourseSchedule::getTimeZoneText($pwId, $code);
                }
                foreach ($courseCodes as $code) {
                    $courseTexts["{$pwId}_{$code}"] = CourseSchedule::getCourseText($pwId, $code);
                }
            }

            foreach ($list as $k => $v) {
                // 确保日期格式为YYYY-MM-DD（补零）
                $formattedDate = $list[$k]['year'] . '-' .
                    str_pad($list[$k]['month'], 2, '0', STR_PAD_LEFT) . '-' .
                    str_pad($list[$k]['day'], 2, '0', STR_PAD_LEFT);

                // 从预查询的结果中获取文本，避免重复查询数据库
                $timeSlotKey = "{$v['publicwelfare_id']}_{$v['time_slot_code']}";
                $communityKey = "{$v['publicwelfare_id']}_{$v['community_code']}";
                $timeZoneKey = "{$v['publicwelfare_id']}_{$v['time_zone_code']}";
                $courseKey = "{$v['publicwelfare_id']}_{$v['course_code']}";

                $list[$k]['time_slot_text'] = $formattedDate . " " .
                    (isset($timeSlotTexts[$timeSlotKey]) ? $timeSlotTexts[$timeSlotKey] : '') .
                    '(' . $v['time_slot_code'] . ")";
                $list[$k]['community_text'] = (isset($communityTexts[$communityKey]) ? $communityTexts[$communityKey] : '') .
                    '(' . $v['community_code'] . ")";
                $list[$k]['time_zone_text'] = (isset($timeZoneTexts[$timeZoneKey]) ? $timeZoneTexts[$timeZoneKey] : '') .
                    '(' . $v['time_zone_code'] . ")";
                $list[$k]['course_text'] = isset($courseTexts[$courseKey]) ? $courseTexts[$courseKey] : '';
            }
            //减少数组数量到10条
            //$list = array_slice($list, 0, 10);
            $result = array(
                "total" => count($list), // 使用数组长度获取总记录数
                "rows" => $list,
                "all_loaded" => true // 标记所有数据已加载
            );

            // 将结果缓存到Redis
            $this->setCacheData($cacheKey, $result, 3600); // 缓存1小时

            return json($result);
            exit;
        }

        // 明确指定模板地址，避免路径解析问题
        return $this->view->fetch('course/schedule/index');
    }

    /**
     * 获取学科列表
     * @param int $publicwelfare_id 项目ID
     * @return \think\response\Json
     */

    public function getSubjectList()
    {
        $publicwelfare_id = $this->request->param('publicwelfare_id', 0, 'intval');

        if (!$publicwelfare_id) {
            return json([]);
        }

        $list = Db::name('fa_community_course_config')
            ->where('publicwelfare_id', $publicwelfare_id)
            ->where('status', 1)
            ->field('id,code, name')
            ->select();

        $result = [];
        foreach ($list as $item) {
            $result[$item['code']] = $item['name'];
        }
        return json(['code' => 1, 'msg' => '获取成功', 'data' => $result]);
    }

    /**
     * 获取社区列表
     * @param int $publicwelfare_id 项目ID
     * @return \think\response\Json
     */
    public function getCommunityList()
    {
        $publicwelfare_id = $this->request->param('publicwelfare_id', 0, 'intval');

        if (!$publicwelfare_id) {
            return json([]);
        }

        $list = Db::name('fa_community_code_config')
            ->where('publicwelfare_id', $publicwelfare_id)
            ->where('status', 1)
            ->field('id, name')
            ->select();

        $result = [];
        foreach ($list as $item) {
            $result[$item['id']] = $item['name'];
        }

        return json(['code' => 1, 'msg' => '获取成功', 'data' => $result]);
    }

    protected function initialize()
    {
        parent::initialize();
        $this->model = new \app\common\model\CourseSchedule;
        $this->view->assign("courseList", $this->model::getCourseList(1, 3));
        $this->view->assign("communityList", $this->model::getCommunityList(1, 3));
        $this->view->assign("timeZoneList", $this->model::getTimeZoneList(1, 3));
        $this->view->assign("timeSlotList", $this->model::getTimeSlotList(1, 3));
        $this->view->assign("monthList", $this->model::getTimeZoneList(1, 3));
        $this->view->assign("statusList", ['0' => __('Disabled'), '1' => __('Normal')]);

        // 获取公益项目列表
        $publicwelfareList = Db::name('fa_community_publicwelfare')
            ->where('status', 1)
            ->field('id, project_name')
            ->select();
        $this->view->assign("publicwelfareList", $publicwelfareList);

        // 注册API路由
        $this->noNeedLogin = ['getCommunityList', 'getSubjectList', 'confirmSchedule', 'checkFormalSchedule', 'cancelSchedule'];
        $this->noNeedRight = ['getCommunityList', 'getSubjectList', 'confirmSchedule', 'checkFormalSchedule', 'cancelSchedule'];
    }


    /**
     * 排课表格
     */
    public function table()
    {
        // 获取参数
        $month = $this->request->get('month', date('n'));
        $year = $this->request->get('year', date('Y'));
        $publicwelfare_id = $this->request->get('publicwelfare_id', 0);
        // 获取社区筛选参数，'0' 代表全部社区
        $community_code_filter = $this->request->get('community_code_filter', '0');
        $subject_id_filter = $this->request->get('subject_id_filter', '0'); // '0' for all subjects

        // 生成页面缓存键
        $pageCacheKey = "schedule:table:page:{$publicwelfare_id}:{$year}:{$month}:{$community_code_filter}:{$subject_id_filter}";

        // 获取用于筛选下拉框的社区列表 (基于当前项目)
        $communityListForDropdown = CourseSchedule::getCommunityList($publicwelfare_id);
        $communityListForDropdown = is_array($communityListForDropdown) ? $communityListForDropdown : []; //确保是数组
        $this->view->assign("communityListForDropdown", $communityListForDropdown);

        // 获取用于筛选下拉框的学科列表 (基于当前项目)
        $subjectListForDropdown = CourseSchedule::getCourseNameList($publicwelfare_id);
        $subjectListForDropdown = is_array($subjectListForDropdown) ? $subjectListForDropdown : []; //确保是数组
        $this->view->assign("subjectListForDropdown", $subjectListForDropdown);

        // 生成缓存键
        $cacheKey = "schedule:table:{$publicwelfare_id}:{$year}:{$month}:{$community_code_filter}:{$subject_id_filter}";

        // 尝试从Redis获取缓存数据
        $cachedViewData = $this->getCacheData($cacheKey);
        if ($cachedViewData !== false) {
            // 将缓存数据分配到视图
            foreach ($cachedViewData as $key => $value) {
                $this->view->assign($key, $value);
            }
            $this->view->assign('community_code_filter', $community_code_filter);
            $this->view->assign('subject_id_filter', $subject_id_filter);
            // 添加isAjaxRequest变量
            $this->view->assign('isAjaxRequest', $this->request->isAjax());

            // 如果是Ajax请求，返回JSON数据
            if ($this->request->isAjax()) {
                $result = [
                    'code' => 1,
                    'msg' => '获取成功',
                    'data' => $cachedViewData
                ];
                $result['data']['community_code_filter'] = $community_code_filter;
                $result['data']['subject_id_filter'] = $subject_id_filter;
                return json($result);
            }
            return $this->view->fetch();
        }

        // 将参数分配到视图
        $this->view->assign('year', $year);
        $this->view->assign('month', $month);
        $this->view->assign('publicwelfare_id', $publicwelfare_id);
        $this->view->assign('community_code_filter', $community_code_filter);
        $this->view->assign('subject_id_filter', $subject_id_filter);
        // 添加isAjaxRequest变量
        $this->view->assign('isAjaxRequest', $this->request->isAjax());

        // 1. 获取排课数据
        $scheduleQuery = Db::name('fa_course_schedule')->where('status', 1);

        // 根据年份筛选
        if ($year > 0) {
            $scheduleQuery->where('year', $year);
        }

        if ($publicwelfare_id > 0) {
            $scheduleQuery->where('publicwelfare_id', $publicwelfare_id);
        }

        // 新增：根据选择的社区编码筛选排课数据
        if ($community_code_filter !== '0') { // $community_code_filter is "1", "2", etc.
            // 假设数据库 fa_course_schedule.community_code 存储的是 "社区1", "社区2" 格式
            $targetCommunityDbKey = "社区" . $community_code_filter;
            $scheduleQuery->where('community_code', $targetCommunityDbKey);
            $targetCommunityDbName = $communityListForDropdown[$targetCommunityDbKey] ?? null;
        }

        // 新增：根据选择的学科中文名筛选排课数据
        if ($subject_id_filter !== '0' && !empty($subject_id_filter)) {
            // $subject_id_filter 现在是课程的中文名，例如 "养生操"

            // 1. 根据中文名从 fa_community_course_config 查找对应的 course code
            //    需要结合当前筛选的 publicwelfare_id 来确保唯一性，
            //    因为 getCourseList 也是基于这个 publicwelfare_id 生成的列表。
            $courseConfigQuery = \think\Db::name('fa_community_course_config')
                ->where('code', $subject_id_filter) // 匹配中文名
                ->where('status', 1)
                ->where('delete_time', null);

            if ($publicwelfare_id > 0) {
                $courseConfigQuery->where('publicwelfare_id', $publicwelfare_id);
            }

            $courseData = $courseConfigQuery->field('code')->find();

            if ($courseData && !empty($courseData['code'])) {
                $targetCourseCode = $courseData['code'];
                // 2. 使用获取到的 course_code 筛选 fa_course_schedule 表
                $scheduleQuery->where('course_code', $targetCourseCode);
            } else {
                // 如果中文名没有找到对应的 code (例如数据不一致或用户篡改),
                // 则不应该匹配到任何排课记录。
                $scheduleQuery->whereRaw('1=0');
            }
        }
        $scheduleQuery->order('year', 'asc');
        $scheduleQuery->order('month', 'asc');
        $scheduleQuery->order('day', 'asc');
        $scheduleQuery->order('timeslot', 'asc');
        $scheduleData = $scheduleQuery->select();

        // 添加排序保持
        usort($scheduleData, function ($a, $b) {
            if ($a['year'] != $b['year']) return $a['year'] - $b['year'];
            if ($a['month'] != $b['month']) return $a['month'] - $b['month'];
            if ($a['day'] != $b['day']) return $a['day'] - $b['day'];

            // 更健壮的时间比较
            $getStartTime = function ($timeStr) {
                $parts = explode('-', $timeStr);
                return count($parts) > 0 ? strtotime($parts[0]) : 0;
            };
            return $getStartTime($a['timeslot']) - $getStartTime($b['timeslot']);
        });

        // 2. 获取时间段详细信息
        $detailedTimeSlots = $this->getTimeSlotDetails($publicwelfare_id);

        // 3. 整理时间段数据，按日期和时间段分组
        $organizedTimeSlots = [];
        foreach ($detailedTimeSlots as $slot) {
            $dayKey = $slot['day'];
            $timeKey = $slot['startTime'] . '-' . $slot['endTime'];

            if (!isset($organizedTimeSlots[$dayKey])) {
                $organizedTimeSlots[$dayKey] = [];
            }

            $organizedTimeSlots[$dayKey][$timeKey] = $slot;
        }

        // 4. 构建课程表格数据
        $tableData = [];
        $debugSchedule = [];
        $debug = [];

        // 获取社区映射信息
        $communityMapping = [];
        $communityIdMapping = [];

        // 从数据库加载社区映射关系
        $communityList = CourseSchedule::getCommunityList($publicwelfare_id);

        // 构建两种映射：社区编码到名称、ID到编码
        foreach ($communityList as $code => $name) {
            $communityMapping[$code] = $name;
        }

        // 获取所有社区的原始记录，用于创建详细的映射关系
        $communityRecords = Db::name('fa_community_code_config')
            ->where('status', 1)
            ->where('delete_time', null);

        if ($publicwelfare_id > 0) {
            $communityRecords->where('publicwelfare_id', $publicwelfare_id);
        }

        $communityRecords = $communityRecords->field('id, code, name')->select();

        // 构建更复杂的映射关系，包括数字ID和编码的映射
        $communityDetailMapping = [];
        foreach ($communityRecords as $record) {
            $communityDetailMapping[$record['id']] = [
                'code' => $record['code'],
                'name' => $record['name']
            ];

            // 也添加编码和名称的映射
            if (!empty($record['code'])) {
                $communityDetailMapping[$record['code']] = [
                    'id' => $record['id'],
                    'name' => $record['name']
                ];
            }

            // 添加名称的映射
            $communityDetailMapping[$record['name']] = [
                'id' => $record['id'],
                'code' => $record['code']
            ];
        }

        foreach ($scheduleData as $schedule) {
            $day = $schedule['day'];
            $courseCode = $schedule['course_code'];
            $communityCode = $schedule['community_code'];
            $month = $schedule['month'];
            $timeSlotCode = $schedule['time_slot_code'];
            $timeslot = isset($schedule['timeslot']) ? $schedule['timeslot'] : '';

            // 构建多种键值格式，增加匹配成功率
            $keyFormats = [];

            // 获取年份信息
            $scheduleYear = isset($schedule['year']) ? $schedule['year'] : $year;

            // 转换为数字字符串的键值格式（包含年份）
            $keyFormats[] = $scheduleYear . '_' . $month . '_' . intval($day) . '_' . $timeSlotCode . '_' . $communityCode;
            $keyFormats[] = intval($day) . '_' . $timeSlotCode . '_' . $communityCode . '_' . $month; // 兼容旧格式

            // 社区名称的键值格式（包含年份）
            if (isset($communityMapping[$communityCode])) {
                $keyFormats[] = $scheduleYear . '_' . $month . '_' . $day . '_' . $timeSlotCode . '_' . $communityMapping[$communityCode];
                $keyFormats[] = $day . '_' . $organizedTimeSlots[$day][$timeSlotCode]["id"] . '_' . $communityCode . '_' . $schedule['time_zone_code']; // 兼容旧格式
            }

            // 将所有键值格式添加到表格数据中
            foreach ($keyFormats as $key) {
                $tableData[$key] = $courseCode;
            }
        }

        // 5. 获取月份数据
        $timeZoneList = CourseSchedule::getTimeZoneList();
        $allMonths = [];
        $newAllMonths = [];

        foreach ($timeZoneList as $code => $name) {
            $formattedCode = sprintf('%02d', intval($code));
            $allMonths[$code] = $name; // 原始编码
            $allMonths[$formattedCode] = $name; // 格式化编码

            // 如果名称不包含年月，使用默认格式
            if (!preg_match('/^\d+年\d+月$/', $name)) {
                $allMonths[$code] = $year . '年' . $code . '月';
                $allMonths[$formattedCode] = $year . '年' . $formattedCode . '月';
            }

            // 如果键名是"时区X"格式，提取数字部分作为新键
            if (preg_match('/^时区(\d+)$/', $code, $matches)) {
                $newKey = intval($matches[1]);
                $newAllMonths[$newKey] = $allMonths[$code];
            }
        }

        // 使用新的数字键数组替换原数组
        if (!empty($newAllMonths)) {
            $allMonths = $newAllMonths;
        }

        // 添加调试信息
        $debugInfo = [];
        $debugInfo['tableDataCount'] = count($tableData);

        // 安全地获取表格数据的键和值
        $tableDataKeys = [];
        $tableDataValues = [];

        // 确保我们只处理数组键
        if (!empty($tableData) && is_array($tableData)) {
            $keys = array_keys($tableData);
            $i = 0;
            foreach ($keys as $key) {
                if ($i >= 200) break; // 只取前20个
                $tableDataKeys[] = $key;
                $tableDataValues[] = $tableData[$key];
                $i++;
            }
        }

        $debugInfo['tableDataKeys'] = $tableDataKeys;
        $debugInfo['tableDataValues'] = $tableDataValues;


        $debugInfo['communityList'] = $communityList;
        $debugInfo['timeSlotList'] = CourseSchedule::getTimeSlotList();
        $year = substr(date('Y'), 2, 2);
        $testYear = '2026';
        $testMonth = '01'; // 两位数格式

        // 添加几个测试数据点
        $testData = [
            // 日期、时间段、社区、课程编码
            ['05', '1', '1', '1'], // 1月5日，时间段1，社区1，课程1（音乐）
            ['10', '2', '2', '2'], // 1月10日，时间段2，社区2，课程2（舞蹈）
            ['15', '3', '3', '3'], // 1月15日，时间段3，社区3，课程3（书法）
            ['20', '4', '1', '4'], // 1月20日，时间段4，社区1，课程4（绘画）
            ['25', '1', '2', '5']  // 1月25日，时间段1，社区2，课程5（钢琴）
        ];

        foreach ($testData as $item) {
            $testDay = $item[0];
            $testTimeSlot = $item[1];
            $testCommunity = $item[2];
            $testCourse = $item[3];

            // 标准键值格式（年_月_日_时间段_社区）
            $key1 = $testYear . '_' . $testMonth . '_' . $testDay . '_' . $testTimeSlot . '_' . $testCommunity;

            // 兼容旧格式（日_时间段_社区_月）
            $key2 = $testDay . '_' . $testTimeSlot . '_' . $testCommunity . '_' . $testMonth;

            // 将课程数据添加到表格数据中
//            $tableData[$key1] = $testCourse;
//            $tableData[$key2] = $testCourse;
        }
        //$allMonths 排除重复
        $allMonths = array_unique($allMonths);


        // 6. 准备视图数据
        $viewData = [
            'month' => $month,
            'year' => $year,
            'targetCommunityDbName' => $targetCommunityDbName ?? '',
            'publicwelfare_id' => $publicwelfare_id,
            'tableData' => $tableData,
            'organizedTimeSlots' => $organizedTimeSlots,
            'courseList' => CourseSchedule::getCourseList($publicwelfare_id),
            'communityList' => CourseSchedule::getCommunityList($publicwelfare_id),
            'timeZoneList' => CourseSchedule::getTimeZoneList($publicwelfare_id),
            'timeSlotList' => CourseSchedule::getTimeSlotList($publicwelfare_id),
            'communityMapping' => $communityMapping,
            'communityDetailMapping' => $communityDetailMapping,
            'debugInfo' => $debugInfo,
            'monthList' => [
                '1' => '1月', '2' => '2月', '3' => '3月', '4' => '4月',
                '5' => '5月', '6' => '6月', '7' => '7月', '8' => '8月',
                '9' => '9月', '10' => '10月', '11' => '11月', '12' => '12月'
            ],
            'allMonths' => $allMonths,
        ];

        // 根据社区筛选参数，确定实际要在表格中渲染的社区列表
        $communityToRender = [];
        // $communityList 在这里是 CourseSchedule::getCommunityList() 的结果，键是 "社区X"
        $sourceCommunityList = isset($viewData['communityList']) && is_array($viewData['communityList']) ? $viewData['communityList'] : [];

        if ($community_code_filter !== '0') { // $community_code_filter 是类似 "1", "2" 的字符串
            // 构建期望的键名，例如 "社区1"
            $targetKey = "社区" . $community_code_filter;
            if (isset($sourceCommunityList[$targetKey])) {
                $communityToRender = [$targetKey => $sourceCommunityList[$targetKey]];
            }
        } else {
            $communityToRender = $sourceCommunityList; // '0' means all communities from the project
        }

        $viewData['communityList'] = $communityToRender; // Use the filtered list for table rows

        // 8. 将数据传递给模板
        $this->view->assign($viewData);

        // 将视图数据缓存到Redis
        $this->setCacheData($cacheKey, $viewData, 3600); // 缓存1小时

        // 如果是Ajax请求，返回JSON数据
        if ($this->request->isAjax()) {
            $result = [
                'code' => 1,
                'msg' => '获取成功',
                'data' => $viewData
            ];
            $result['data']['community_code_filter'] = $community_code_filter;
            $result['data']['subject_id_filter'] = $subject_id_filter;
            return json($result);
        }

        // 渲染页面内容
        $pageContent = $this->view->fetch();

        // 将页面内容缓存到Redis
        $pageCacheData = ['html' => $pageContent];
        $this->setCacheData($pageCacheKey, $pageCacheData, 3600); // 缓存1小时

        return $pageContent;
    }

    /**
     * 自动社区排课
     */
    public function generate()
    {
        // 获取项目id参数，默认使用URL中的参数或会话中的值
        $publicwelfare_id = $this->request->get('publicwelfare_id', 0);
        if (empty($publicwelfare_id) && isset($_SESSION['think']['admin']['publicwelfare_id'])) {
            $publicwelfare_id = $_SESSION['think']['admin']['publicwelfare_id'];
        }

        if ($this->request->isPost()) {
            $params = $this->request->post();

            $publicwelfare_id = isset($params['publicwelfare_id']) ? intval($params['publicwelfare_id']) : $publicwelfare_id;

            if (empty($publicwelfare_id)) {
                $this->error('请选择项目');
            }

            // 获取该项目下的课程、社区、时区和时间段
            $courseData = $this->getCourseData($publicwelfare_id);
            $communityData = $this->getCommunityData($publicwelfare_id);
            $timeZoneData = $this->getTimeZoneData($publicwelfare_id);
            $timeSlotData = $this->getTimeSlotData($publicwelfare_id);

            $courses = array_keys($courseData);
            $communities = array_keys($communityData);
            $timeZones = array_keys($timeZoneData);

            // 检查数据库中已存在的社区，确保包含所有需要排课的社区
            $existingCommunities = Db::name('fa_course_schedule')
                ->where('publicwelfare_id', $publicwelfare_id)
                ->distinct(true)
                ->column('community_code');

            // 将数据库中存在但配置中没有的社区也加入排课列表
            foreach ($existingCommunities as $communityCode) {
                if (!isset($communityData[$communityCode])) {
                    // 尝试从配置表获取社区名称
                    $communityName = Db::name('fa_community_code_config')
                        ->where('code', $communityCode)
                        ->value('name');

                    if (!$communityName) {
                        // 如果配置表中也没有，使用代码作为名称
                        $communityName = $communityCode;
                    }

                    $communityData[$communityCode] = $communityName;
                    $communities[] = $communityCode;
                    $debugInfo[] = "添加数据库中的社区到排课列表: {$communityCode} => {$communityName}";
                }
            }

            // 添加详细的调试信息
            $debugInfo = [];
            $debugInfo[] = "=== 排课开始 ===";
            $debugInfo[] = "项目ID: {$publicwelfare_id}";
            $debugInfo[] = "课程总数: " . count($courses) . " (" . implode(', ', array_values($courseData)) . ")";
            $debugInfo[] = "社区总数: " . count($communities);


            // 检查现有的排课记录
            $debugInfo[] = "=== 检查现有排课记录 ===";
            $existingSchedules = Db::name('fa_course_schedule')
                ->where('publicwelfare_id', $publicwelfare_id)
                ->field('community_code, course_code, COUNT(*) as count')
                ->group('community_code')
                ->select();


            // 计算每个社区需要安排的课程数量
            $coursesPerCommunity = count($courses);
            $debugInfo[] = "每个社区需要安排课程数: {$coursesPerCommunity}";

            // 获取详细时间段数据
            $detailedTimeSlots = $this->getTimeSlotDetails($publicwelfare_id);

            // 按年、月、日、开始时间排序
            usort($detailedTimeSlots, function ($a, $b) {
                if ($a['year'] != $b['year']) {
                    return $a['year'] - $b['year'];
                }
                if ($a['month'] != $b['month']) {
                    return $a['month'] - $b['month'];
                }
                if ($a['day'] != $b['day']) {
                    return $a['day'] - $b['day'];
                }
                return strcmp($a['startTime'], $b['startTime']);
            });

            // 1. 按月份分组日期
            $datesByMonth = [];
            foreach ($detailedTimeSlots as $timeSlot) {
                $monthKey = $timeSlot['year'] . '-' . $timeSlot['month'];
                $dateKey = $timeSlot['year'] . '-' . $timeSlot['month'] . '-' . $timeSlot['day'];

                if (!isset($datesByMonth[$monthKey])) {
                    $datesByMonth[$monthKey] = [];
                }

                if (!isset($datesByMonth[$monthKey][$dateKey])) {
                    $datesByMonth[$monthKey][$dateKey] = [];
                }

                $datesByMonth[$monthKey][$dateKey][] = $timeSlot;
            }

            // 4. 开始排课
            try {
                Db::startTrans();

                // 按月份排序
                uksort($datesByMonth, function ($a, $b) {
                    return strtotime($a) - strtotime($b);
                });

                // 初始化变量
                $communityCoursesAssigned = [];
                $communityDateCoursesAssigned = [];
                foreach ($communities as $communityId) {
                    $communityCoursesAssigned[$communityId] = 0;
                    $communityDateCoursesAssigned[$communityId] = [];
                }

                $communityTimeSlotUsed = [];
                $courseTimeSlotUsed = [];
                $communityCoursesTaken = [];

                // 清空该项目的旧排课数据
                Db::name('fa_course_schedule')->where('publicwelfare_id', $publicwelfare_id)->delete();
                $debugInfo[] = "已清空项目 {$publicwelfare_id} 的旧排课数据";

                // 初始化每个社区的课程记录
                foreach ($communities as $communityId) {
                    $communityCoursesTaken[$communityId] = [];
                }

                // 主排课循环
                $loopCount = 0;
                $insertCount = 0;
                $debugInfo[] = "=== 开始主排课循环 ===";
                $debugInfo[] = "月份数: " . count($datesByMonth);
                foreach ($datesByMonth as $monthKey => $datesInMonth) {
                    $debugInfo[] = "处理月份: {$monthKey}, 包含日期数: " . count($datesInMonth);
                    foreach ($datesInMonth as $dateKey => $timeSlotsInDate) {
                        //$debugInfo[] = "处理日期: {$dateKey}, 包含时间段数: " . count($timeSlotsInDate);
                        foreach ($timeSlotsInDate as $timeSlot) {
                            // 修改开始：创建一个时间槽使用标记，用于确保同一时间同一课程只分配给一个社区
                            $timeSlotUsedForCourse = [];

                            foreach ($communities as $communityId) {
                                $loopCount++;
                                // 检查社区是否已安排完所有课程
                                if ($communityCoursesAssigned[$communityId] >= $coursesPerCommunity) {
                                    continue;
                                }

                                // 检查社区是否已在当天安排过课程
                                if (isset($communityDateCoursesAssigned[$communityId]) &&
                                    is_array($communityDateCoursesAssigned[$communityId]) &&
                                    isset($communityDateCoursesAssigned[$communityId][$dateKey]) &&
                                    $communityDateCoursesAssigned[$communityId][$dateKey] > 0) {
                                    // 如果社区当天已排课，则跳过
                                    continue;
                                }

                                // 生成唯一键检查时间段是否已使用
                                $timeSlotKey = $communityId . '_';
                                if (is_array($timeSlot)) {
                                    $timeSlotKey .= $timeSlot['year'] . '_' .
                                        $timeSlot['month'] . '_' .
                                        $timeSlot['day'] . '_' .
                                        $timeSlot['startTime'] . '-' .
                                        $timeSlot['endTime'];
                                } else {
                                    $timeSlotKey .= $timeSlot;
                                }

                                // 检查时间段是否已使用
                                if (isset($communityTimeSlotUsed[$timeSlotKey])) {
                                    continue;
                                }

                                // 构建时间标识符（不包含社区信息）
                                $timeIdentifier = '';
                                if (is_array($timeSlot)) {
                                    $timeIdentifier = $timeSlot['year'] . '_' .
                                        $timeSlot['month'] . '_' .
                                        $timeSlot['day'] . '_' .
                                        $timeSlot['startTime'] . '-' .
                                        $timeSlot['endTime'];
                                } else {
                                    $parts = explode(' ', $timeSlot);
                                    if (count($parts) >= 2) {
                                        $timeIdentifier = $parts[0] . '_' . $parts[1]; // 日期_时间段
                                    }
                                }

                                // 获取该社区可用的课程
                                $availableCourses = array_map(function ($id) use ($communityId, $courseData) {
                                    return [
                                        'id' => $id,
                                        'name' => $courseData[$id],
                                        'community_id' => $communityId // 假设所有课程都适用于当前社区
                                    ];
                                }, array_keys($courseData));

                                // 过滤掉已在同一时间安排的课程，不管哪个社区
                                $availableCourses = array_filter($availableCourses, function ($course) use ($timeIdentifier, $courseTimeSlotUsed, $communityId, $communityCoursesTaken, $timeSlotUsedForCourse) {
                                    $courseTimeKey = $course['id'] . '_' . $timeIdentifier;

                                    // 检查该课程是否已经被安排在该时间段（修改：检查当前时间槽是否已分配该课程）
                                    $timeSlotAvailable = !isset($courseTimeSlotUsed[$courseTimeKey]) && !isset($timeSlotUsedForCourse[$course['id']]);

                                    // 检查社区是否已经上过这门课程
                                    $courseNotTakenByCommunity = !in_array($course['id'], $communityCoursesTaken[$communityId] ?? []);

                                    // 只有两个条件都满足才返回true
                                    return $timeSlotAvailable && $courseNotTakenByCommunity;
                                });

                                // 添加调试信息
                                if (empty($availableCourses)) {
                                    continue;
                                }

                                // 按课程ID从小到大排序选择课程
                                usort($availableCourses, function ($a, $b) {
                                    // 使用intval将字符串ID转换为整数进行比较
                                    return intval($a['id']) - intval($b['id']);
                                });
                                $course = $availableCourses[0]; // 选择排序后的第一个课程

                                try {
                                    // 创建排课记录
                                    $dateParts = is_array($timeSlot) ? null : explode('-', explode(' ', $timeSlot)[0]);
                                    $timeSlotCode = is_array($timeSlot) ? $timeSlot['startTime'] . "-" . $timeSlot['endTime'] : ($timeSlot['code'] ?? 0);
                                    $timeZoneCode = is_array($timeSlot) ? ($timeSlot['time_zone_code'] ?? '') : '';

                                    $scheduleData = [
                                        'publicwelfare_id' => $publicwelfare_id,
                                        'school_id' => session('admin.school_id') ? session('admin.school_id') : 0, // 使用session函数安全获取学校ID
                                        'community_code' => $communityId,
                                        'course_code' => $course['id'],
                                        'year' => is_array($timeSlot) ? $timeSlot['year'] : $dateParts[0],
                                        'month' => is_array($timeSlot) ? $timeSlot['month'] : $dateParts[1],
                                        'day' => is_array($timeSlot) ? $timeSlot['day'] : $dateParts[2],
                                        'time_slot_code' => $timeSlotCode,
                                        'time_zone_code' => $timeZoneCode,
                                        'timeslot' => is_array($timeSlot) ? ($timeSlot['startTime'] . '-' . $timeSlot['endTime']) : $timeSlot,
                                        'status' => 1,
                                        'create_time' => time(),
                                        'update_time' => time()
                                    ];

                                    // 插入排课记录
                                    $schedule_id = $this->model->insertUpdate($scheduleData, ["year", "month", "day", "time_slot_code", "community_code", "course_code"]);
                                    $insertCount++;

                                    // 请在这里组织数据，插入到 Autoplantemp 表,参考autoplan.php的排课数据用insertUpdate方法
                                    // 获取课程信息
                                    $courseInfo = Db::name('community_course_config')
                                        ->where('code', $course['id'])
                                        ->where('publicwelfare_id', $publicwelfare_id)
                                        ->find();

                                    // 获取ocation信息
                                    $ocationInfo = Db::name('fa_community_code_config')
                                        ->alias("cc")
                                        ->join("fa_ocation o","o.name=cc.name")
                                        ->where('code', $communityId)
                                        ->where('publicwelfare_id', $publicwelfare_id)
                                        ->field("o.*")
                                        ->find();
                                    $ocation_id=$ocationInfo['id'];
                                    if ($ocationInfo) {
                                        $community_id = $this->findCommunityIdRecursive($ocationInfo['id']);
                                        if (!$community_id) {
                                            $community_id = $ocationInfo['id'];
                                        }
                                    } else {
                                        $community_id = 0;
                                    }

                                    // 获取公益项目信息
                                    $publicwelfareInfo = Db::name('fa_community_publicwelfare')
                                        ->where('id', $publicwelfare_id)
                                        ->find();

                                    // 获取社区名称
                                    $communityName = $communityData[$communityId] ?? $communityId;

                                    // 获取课程名称
                                    $courseName = $courseData[$course['id']] ?? $course['id'];

                                    // 构造班级名称：社区名+课程名+公益项目名
                                    $className = "【" . $communityName . "】" . $courseName . ($publicwelfareInfo['project_name'] ?? '');

                                    $parentOcations=model("\app\admin\model\Ocation")->getParentOcations($ocation_id);
                                    $parentTeachingOcationId=$parentOcations["parentTeachingOcationId"];
                                    $topTeachingOcationId=$parentOcations["topTeachingOcationId"];
                                    $areaTeachingOcationId=$parentOcations["areaTeachingOcationId"];

                                    $courseTimeKey=0;

                                    // 构造班级数据
                                    $classData = [
                                        'rel_type' => session('admin.rel_type'), // 社区类型
                                        'rel_id' => session('admin.rel_id'), // 社区ID
                                        'school_id' => session('admin.school_id'), // 使用session函数安全获取学校ID
                                        'classes_type' => 2, // 默认班级类型
                                        'nianji' => '', // 年级（社区排课可为空）
                                        'community_id' => $community_id, // 社区ID
                                        'xueqi' => '', // 默认春季
                                        'qishu' => $courseInfo['id'], // 默认期数1
                                        'class_type' => 1, // 班级类型
                                        'subject_lv' => $courseInfo['id'],
                                        'status' => 1,
                                        'class_index' => 1, // 默认第1节课
                                        'oindex' => 1, // 默认第1节
                                        'oindex_count' => 1, // 默认1节课
                                        'count_total' => 1, // 默认总共1节课
                                        'bz' => '自动排课生成',
                                        // 新增字段
                                        'parent_teaching_ocation_id' => $parentTeachingOcationId, // 上级教学点ID
                                        'top_teaching_ocation_id' => $topTeachingOcationId, // 一级教学点ID
                                        'area_teaching_ocation_id' => $areaTeachingOcationId, // 一级教学点ID
                                        'school_id' => session('admin.school_id') ? session('admin.school_id') : 0, // 使用session函数安全获取学校ID
                                        'project_id' => $publicwelfare_id, // 项目ID
                                        'community_id' => $community_id, // 社区ID
                                        'is_free' => 1, // 是否免费
                                        'subject_lv' => $courseInfo['id'], // 学科ID
                                    ];

                                    // 更新记录状态
                                    $communityTimeSlotUsed[$timeSlotKey] = true;
                                    $courseTimeSlotUsed[$courseTimeKey] = true;

                                    // 修改开始：标记该时间槽已使用此课程
                                    $timeSlotUsedForCourse[$course['id']] = true;
                                    // 修改结束

                                    // 记录该社区已经上过的课程
                                    $communityCoursesTaken[$communityId][] = $course['id'];

                                    // 更新社区课程计数
                                    $communityCoursesAssigned[$communityId]++;

                                    // 更新社区当天课程计数
                                    if (!isset($communityDateCoursesAssigned[$communityId][$dateKey])) {
                                        $communityDateCoursesAssigned[$communityId][$dateKey] = 0;
                                    }
                                    $communityDateCoursesAssigned[$communityId][$dateKey]++;

                                    $courseName = $courseData[$course['id']] ?? $course['id'];
                                    $communityName = $communityData[$communityId] ?? $communityId;

                                    //$debugInfo[] = "排课成功: {$communityName}({$communityId}) - {$courseName}({$course['id']}) - {$scheduleData['year']}-{$scheduleData['month']}-{$scheduleData['day']} {$scheduleData['timeslot']}";
                                } catch (\Exception $e) {
                                    $debugInfo[] = "排课失败: " . $e->getMessage();
                                    continue;
                                }
                            }
                        }
                    }
                }
                $debugInfo[] = "主排课循环总执行次数: {$loopCount}";
                $debugInfo[] = "实际插入记录数: {$insertCount}";

                // 主排课循环结束后，添加详细的统计信息
                $debugInfo[] = "=== 主排课结束，统计结果 ===";
                foreach ($communities as $communityId) {
                    $assigned = $communityCoursesAssigned[$communityId] ?? 0;
                    $communityName = $communityData[$communityId] ?? $communityId;
                    //$debugInfo[] = "社区 {$communityId}({$communityName}) 实际安排课程数: {$assigned}/{$coursesPerCommunity}";
                }

                // 在补课检查前，重新统计每个社区的实际课程数
                $debugInfo[] = "=== 重新统计每个社区的实际课程数 ===";
                $actualCommunityCourseCounts = [];

                foreach ($communityData as $communityCode => $communityName) {
                    $actualCount = Db::name('fa_course_schedule')
                        ->where('publicwelfare_id', $publicwelfare_id)
                        ->where('community_code', $communityCode)
                        ->count();
                    $actualCommunityCourseCounts[$communityCode] = $actualCount;
                }

                // 检查是否有社区名称包含"凤翔"但代码不匹配的情况
                $allSchedules = Db::name('fa_course_schedule')
                    ->where('publicwelfare_id', $publicwelfare_id)
                    ->field('community_code, COUNT(*) as count')
                    ->group('community_code')
                    ->select();

                foreach ($allSchedules as $schedule) {

                    // 检查是否包含凤翔
                    if (strpos($schedule['community_code'], '凤翔') !== false) {
                        $debugInfo[] = "*** 发现凤翔社区: {$schedule['community_code']} 只有 {$schedule['count']} 门课程 ***";

                        // 检查这个社区代码是否在我们的社区列表中
                        if (!isset($communityData[$schedule['community_code']])) {
                            $debugInfo[] = "*** 警告: 凤翔社区代码 '{$schedule['community_code']}' 不在社区配置列表中! ***";

                            // 查找这个社区在配置表中的实际记录
                            $communityConfig = Db::name('fa_community_code_config')
                                ->where('code', $schedule['community_code'])
                                ->orWhere('name', 'like', '%凤翔%')
                                ->field('code, name, status')
                                ->find();

                            if ($communityConfig) {
                                $debugInfo[] = "凤翔社区配置: 代码={$communityConfig['code']}, 名称={$communityConfig['name']}, 状态={$communityConfig['status']}";
                            } else {
                                $debugInfo[] = "未找到凤翔社区的配置记录";
                            }
                        }
                    }
                }

                // 改进的补充排课机制
                $debugInfo[] = "=== 开始补充排课检查 ===";

                // 获取所有需要排课的社区（包括数据库中存在的）
                $allCommunitiesNeedingSchedule = array_unique(array_merge(
                    array_keys($communityData),
                    $existingCommunities
                ));

                $incompleteCommunities = [];

                foreach ($allCommunitiesNeedingSchedule as $communityCode) {
                    $actualCount = Db::name('fa_course_schedule')
                        ->where('publicwelfare_id', $publicwelfare_id)
                        ->where('community_code', $communityCode)
                        ->count();

                    if ($actualCount < $coursesPerCommunity) {
                        $needed = $coursesPerCommunity - $actualCount;
                        $incompleteCommunities[$communityCode] = $needed;

                        $communityName = $communityData[$communityCode] ?? $communityCode;
                        $debugInfo[] = "社区未完成: {$communityCode}({$communityName}) 现有 {$actualCount} 门，还需要 {$needed} 门课程";

                        // 特别标记凤翔社区
                        if (strpos($communityCode, '凤翔') !== false || $communityCode === '社区64') {
                            $debugInfo[] = "*** 凤翔社区需要补充排课: {$communityCode} 还需要 {$needed} 门课程 ***";
                        }
                    }
                }

                // 补充排课逻辑 - 已屏蔽
                if (!empty($incompleteCommunities)) {
                    $debugInfo[] = "开始为 " . count($incompleteCommunities) . " 个社区补充排课";

                    foreach ($incompleteCommunities as $communityCode => $needed) {
                        $debugInfo[] = "正在为社区 {$communityCode} 补充 {$needed} 门课程";

                        for ($i = 0; $i < $needed; $i++) {
                            // 查找可用的时间段和课程
                            $availableSlot = null;
                            $availableCourse = null;

                            foreach ($detailedTimeSlots as $timeSlot) {
                                $timeSlotKey = $this->generateTimeSlotKey(
                                    $timeSlot,
                                    $communityCode
                                );

                                // 检查这个时间段是否已被该社区使用
                                if (isset($communityTimeSlotUsed[$timeSlotKey])) {
                                    continue;
                                }

                                // 查找可用课程
                                foreach ($courses as $courseCode) {
                                    $timeIdentifier = $timeSlot['year'] . '_' .
                                        $timeSlot['month'] . '_' .
                                        $timeSlot['day'] . '_' .
                                        $timeSlot['startTime'] . '-' .
                                        $timeSlot['endTime'];
                                    $courseTimeSlotKey = $courseCode . '_' . $timeIdentifier;

                                    // 检查课程在该时间段是否已被使用
                                    if (isset($courseTimeSlotUsed[$courseTimeSlotKey])) {
                                        continue;
                                    }

                                    $availableSlot = $timeSlot;
                                    $availableCourse = $courseCode;
                                    break 2;
                                }
                            }

                            if ($availableSlot && $availableCourse) {
                                // 创建排课记录
                                $scheduleData = [
                                    'publicwelfare_id' => $publicwelfare_id,
                                    'community_code' => $communityCode,
                                    'course_code' => $availableCourse,
                                    'year' => $availableSlot['year'],
                                    'month' => $availableSlot['month'],
                                    'day' => $availableSlot['day'],
                                    'time_slot_code' => $availableSlot['id'],
                                    'time_zone_code' => $availableSlot['time_zone_code'] ?? '',
                                    'timeslot' => $availableSlot['startTime'] . '-' . $availableSlot['endTime'],
                                    'status' => 1,
                                    'create_time' => time(),
                                    'update_time' => time(),
                                    'remark' => '补充排课'
                                ];

                                Db::name('fa_course_schedule')->insert($scheduleData);

                                // 更新使用记录
                                $timeSlotKey = $this->generateTimeSlotKey(
                                    $availableSlot,
                                    $communityCode
                                );

                                $communityTimeSlotUsed[$timeSlotKey] = true;
                                $timeIdentifier = $availableSlot['year'] . '_' .
                                    $availableSlot['month'] . '_' .
                                    $availableSlot['day'] . '_' .
                                    $availableSlot['startTime'] . '-' .
                                    $availableSlot['endTime'];
                                $courseTimeSlotUsed[$availableCourse . '_' . $timeIdentifier] = true;

                                $courseName = $courseData[$availableCourse] ?? $availableCourse;
                                $communityName = $communityData[$communityCode] ?? $communityCode;

                                $debugInfo[] = "补充排课成功: {$communityName}({$communityCode}) - {$courseName}({$availableCourse}) - {$availableSlot['year']}-{$availableSlot['month']}-{$availableSlot['day']} {$availableSlot['startTime']}-{$availableSlot['endTime']}";

                                // 特别标记凤翔社区的补充排课
                                if (strpos($communityCode, '凤翔') !== false || $communityCode === '社区64') {
                                    $debugInfo[] = "*** 凤翔社区补充排课: {$courseName} ***";
                                }
                            } else {
                                $debugInfo[] = "警告: 无法为社区 {$communityCode} 找到可用的时间段和课程";
                            }
                        }
                    }
                } else {
                    $debugInfo[] = "所有社区课程安排完整，无需补课";
                }

                // 添加调试信息说明补充排课已被屏蔽
                $debugInfo[] = "补充排课功能已被屏蔽";

                // 新增：调用教学点课程表更新方法
                $updateResult = $this->updateOcationClasses($publicwelfare_id, $debugInfo);
                if ($updateResult['code'] == 0) {
                    Db::rollback();
                    $this->error('排课完成但更新教学点课程表失败: ' . $updateResult['msg']);
                }

                // 合并调试信息
                $debugInfo = array_merge($debugInfo, $updateResult['debug'] ?? []);

                // 清除相关缓存
                $this->clearCacheByPublicwelfareId($publicwelfare_id);

                Db::commit();
                $this->success('排课完成<br/>' . implode('<br/>', $debugInfo));
            } catch (Exception $e) {
                Db::rollback();
                $this->error('排课失败: ' . $e->getMessage());
            }
        }

        $this->view->assign('publicwelfare_id', $publicwelfare_id);
        return $this->view->fetch();
    }

    /**
     * 更新教学点课程表
     * @param int $publicwelfare_id 公益项目ID
     * @param array $debugInfo 调试信息数组
     * @return array 返回结果
     */
    protected function updateOcationClasses($publicwelfare_id, &$debugInfo = [])
    {
        try {
            $debugInfo[] = "=== 开始更新教学点课程表 ===";

            // 1. 获取自动排课生成的数据
            $scheduleData = Db::name('fa_course_schedule')
                ->where('publicwelfare_id', $publicwelfare_id)
                ->where('status', 1)
                ->select();

            if (empty($scheduleData)) {
                $debugInfo[] = "未找到排课数据，跳过教学点课程表更新";
                return ['code' => 1, 'msg' => '成功', 'debug' => $debugInfo];
            }

            $debugInfo[] = "找到 " . count($scheduleData) . " 条排课记录";

            // 2. 按教学点分组排课数据
            $ocationScheduleData = [];
            foreach ($scheduleData as $schedule) {
                $ocationId = $schedule['ocation_id'] ?? 0;
                if ($ocationId > 0) {
                    if (!isset($ocationScheduleData[$ocationId])) {
                        $ocationScheduleData[$ocationId] = [];
                    }
                    $ocationScheduleData[$ocationId][] = $schedule;
                }
            }

            $debugInfo[] = "涉及 " . count($ocationScheduleData) . " 个教学点";

            // 3. 更新每个教学点的课程表
            foreach ($ocationScheduleData as $ocationId => $schedules) {
                $result = $this->updateSingleOcationClass($ocationId, $schedules, $debugInfo);
                if ($result['code'] == 0) {
                    return $result;
                }
            }

            $debugInfo[] = "=== 教学点课程表更新完成 ===";
            return ['code' => 1, 'msg' => '更新成功', 'debug' => $debugInfo];

        } catch (\Exception $e) {
            $debugInfo[] = "更新教学点课程表失败: " . $e->getMessage();
            file_put_contents($_SERVER["DOCUMENT_ROOT"] . "/../runtime/log/ocation_class_update_error.log",
                date('Y-m-d H:i:s') . " - " . $e->getMessage() . "\n", FILE_APPEND);
            return ['code' => 0, 'msg' => $e->getMessage(), 'debug' => $debugInfo];
        }
    }

    /**
     * 更新单个教学点的课程表
     * @param int $ocationId 教学点ID
     * @param array $schedules 排课数据
     * @param array $debugInfo 调试信息数组
     * @return array 返回结果
     */
    protected function updateSingleOcationClass($ocationId, $schedules, &$debugInfo = [])
    {
        try {
            // 1. 获取教学点信息
            $ocation = Db::name('fa_ocation')->where('id', $ocationId)->find();
            if (!$ocation) {
                $debugInfo[] = "教学点ID {$ocationId} 不存在，跳过";
                return ['code' => 1, 'msg' => '成功'];
            }

            $debugInfo[] = "处理教学点: {$ocation['name']} (ID: {$ocationId})";

            // 2. 查询现有的教学点课程记录
            $existingOcationClass = Db::name('fa_ocation_class')
                ->where('ocation_id', $ocationId)
                ->find();

            // 3. 准备教学点课程数据
            $ocationClassData = [
                'ocation_id' => $ocationId,
                'name' => $ocation['name'] . '班',
                'original_name' => $ocation['name'],
                'status' => 1,
                'weigh' => 0,
                'update_time' => date('Y-m-d H:i:s'),
                'community_id' => $schedules[0]['community_id'] ?? null,
                'description' => '自动排课生成，包含' . count($schedules) . '个课程'
            ];

            $ocationClassId = null;

            if ($existingOcationClass) {
                // 更新现有记录
                Db::name('fa_ocation_class')
                    ->where('id', $existingOcationClass['id'])
                    ->update($ocationClassData);
                $ocationClassId = $existingOcationClass['id'];
                $debugInfo[] = "更新现有教学点课程记录: {$ocation['name']}班";
            } else {
                // 创建新记录
                $ocationClassData['sequence_number'] = \app\admin\model\OcationClass::getNextSequence();
                $ocationClassData['create_time'] = date('Y-m-d H:i:s');
                $ocationClassId = Db::name('fa_ocation_class')->insertGetId($ocationClassData);
                $debugInfo[] = "创建新教学点课程记录: {$ocation['name']}班";
            }

            // 4. 更新课程关联关系
            $result = $this->updateOcationClassCourses($ocationClassId, $schedules, $debugInfo);
            if ($result['code'] == 0) {
                return $result;
            }

            return ['code' => 1, 'msg' => '成功'];

        } catch (\Exception $e) {
            $debugInfo[] = "更新教学点 {$ocationId} 课程表失败: " . $e->getMessage();
            return ['code' => 0, 'msg' => $e->getMessage()];
        }
    }

    /**
     * 更新教学点课程关联关系
     * @param int $ocationClassId 教学点课程ID
     * @param array $schedules 排课数据
     * @param array $debugInfo 调试信息数组
     * @return array 返回结果
     */
    protected function updateOcationClassCourses($ocationClassId, $schedules, &$debugInfo = [])
    {
        try {
            // 2. 从排课数据中提取班级ID
            $scheduleClassIds = [];
            foreach ($schedules as $schedule) {
                if (!empty($schedule['classes_id'])) {
                    $scheduleClassIds[] = $schedule['classes_id'];
                }
            }

            $scheduleClassIds = array_unique($scheduleClassIds);
            $debugInfo[] = "需要关联的班级数量: " . count($scheduleClassIds);

            // 3. 由于class_id有唯一约束，需要特殊处理
            $successCount = 0;
            $conflictCount = 0;
            $updateCount = 0;

            foreach ($scheduleClassIds as $classId) {
                // 检查该class_id是否已经存在于任何教学点班级中
                $existingRecord = Db::name('fa_ocation_class_course')
                    ->where('class_id', $classId)
                    ->find();

                if ($existingRecord) {
                    if ($existingRecord['ocation_class_id'] == $ocationClassId) {
                        // 如果已经关联到当前教学点班级，只需要确保状态为1
                        if ($existingRecord['status'] != 1) {
                            Db::name('fa_ocation_class_course')
                                ->where('id', $existingRecord['id'])
                                ->update([
                                    'status' => 1,
                                    'update_time' => date('Y-m-d H:i:s')
                                ]);
                            $updateCount++;
                        }
                    } else {
                        // 如果已经关联到其他教学点班级，需要转移关联
                        Db::name('fa_ocation_class_course')
                            ->where('id', $existingRecord['id'])
                            ->update([
                                'ocation_class_id' => $ocationClassId,
                                'status' => 1,
                                'update_time' => date('Y-m-d H:i:s')
                            ]);
                        $updateCount++;
                        $debugInfo[] = "转移班级 {$classId} 的关联到当前教学点班级";
                    }
                } else {
                    // 如果不存在，则新增记录
                    try {
                        Db::name('fa_ocation_class_course')->insert([
                            'ocation_class_id' => $ocationClassId,
                            'class_id' => $classId,
                            'status' => 1,
                            'create_time' => date('Y-m-d H:i:s'),
                            'update_time' => date('Y-m-d H:i:s')
                        ]);
                        $successCount++;
                    } catch (\Exception $e) {
                        $conflictCount++;
                        $debugInfo[] = "班级 {$classId} 插入失败，可能存在并发冲突: " . $e->getMessage();
                    }
                }
            }

            if ($successCount > 0) {
                $debugInfo[] = "新增课程关联记录: {$successCount} 条";
            }
            if ($updateCount > 0) {
                $debugInfo[] = "更新课程关联记录: {$updateCount} 条";
            }
            if ($conflictCount > 0) {
                $debugInfo[] = "冲突的课程关联记录: {$conflictCount} 条";
            }

            return ['code' => 1, 'msg' => '成功'];

        } catch (\Exception $e) {
            $debugInfo[] = "更新课程关联关系失败: " . $e->getMessage();
            return ['code' => 0, 'msg' => $e->getMessage()];
        }
    }

    /**
     * 获取课程数据，使用整数ID作为键值
     */
    protected function getCourseData($publicwelfare_id = 0)
    {
        // 从数据库直接获取课程数据，确保使用整数ID
        $courses = Db::name('fa_community_course_config')
            ->where('status', 1)
            ->where('delete_time', null)
            ->field('code, name')
            ->select();

        $list = [];
        foreach ($courses as $course) {
            $list[$course['code']] = $course['name'];
        }

        // 如果没有数据，返回默认列表
        if (empty($list)) {
            return [
                1 => '音乐',
                2 => '舞蹈',
                3 => '书法',
                4 => '绘画',
                5 => '钢琴',
                6 => '太极',
                7 => '剪纸',
                8 => '中医',
                9 => '国画',
                10 => '生活',
                11 => '运动',
                12 => '主持'
            ];
        }

        return $list;
    }

    /**
     * 获取社区数据，使用整数ID作为键值
     */
    protected function getCommunityData($publicwelfare_id = 0)
    {
        // 从数据库直接获取社区数据，确保使用整数ID
        $communities = Db::name('fa_community_code_config')
            ->where('status', 1)
            ->field('code, name')
            ->select();

        $list = [];
        foreach ($communities as $community) {
            $list[$community['code']] = $community['name'];
        }

        // 如果没有数据，返回默认列表
        if (empty($list)) {
            $list = [];
            for ($i = 1; $i <= 5; $i++) {
                $list[$i] = chr(64 + $i) . '社区'; // A-E社区
            }
        }

        return $list;
    }

    /**
     * 获取时区数据，使用整数ID作为键值
     */
    protected function getTimeZoneData($publicwelfare_id = 0)
    {
        // 从数据库直接获取时区数据，确保使用整数ID
        $timezones = Db::name('community_timezone_config')
            ->where('status', 1)
            ->where('delete_time', null)
            ->field('code, name')
            ->select();

        $list = [];
        foreach ($timezones as $timezone) {
            $list[$timezone['code']] = $timezone['name'];
        }

        // 如果没有数据，返回默认列表
        if (empty($list)) {
            return [
                1 => '上午',
                2 => '下午',
                3 => '晚上'
            ];
        }

        return $list;
    }

    /**
     * 获取时间段的详细信息，包括天数
     */
    protected function getTimeSlotDetails($publicwelfare_id = 0)
    {
        // 从数据库直接获取时间段数据
        $result = Db::name('fa_community_timeslot_config')
            ->where('status', 1)
            ->where('delete_time', null)
            ->field('id, code, name, day, start_time, end_time')
            ->select();
        $this->timeSlotDetails = $result;

        // 获取时区数据，用于获取年份和月份
        // 修改开始：根据项目开始日期动态生成时区数据
        $projectInfo = Db::name('fa_community_publicwelfare')
            ->where('id', $publicwelfare_id)
            ->field('start_time,community_id')
            ->find();

        if ($projectInfo && !empty($projectInfo['start_time'])) {
            $startDate = $projectInfo['start_time'];
            $startYear = date('Y', $startDate);
            $startMonth = date('n', $startDate);
            $community_id = $projectInfo['community_id'];
            // 检查现有数据是否从正确的月份开始
            $firstTimeZone = Db::name('fa_community_timezone_config')
                ->order('id', 'asc')
                ->find();

            $needRegenerate = true;
            if ($firstTimeZone) {
                // 检查第一条记录是否匹配开始日期
                if (preg_match('/(\d+)年(\d+)月/', $firstTimeZone['name'], $matches)) {
                    $firstYear = (int)$matches[1];
                    $firstMonth = (int)$matches[2];
                    if ($firstYear == $startYear && $firstMonth == $startMonth) {
                        $needRegenerate = false;
                    }
                }
            }

            if ($needRegenerate) {
                // 清空现有数据并重新生成6个月的记录
                Db::name('fa_community_timezone_config')->where('1=1')->delete();

                for ($i = 0; $i < 6; $i++) {
                    $currentMonth = $startMonth + $i;
                    $currentYear = $startYear;

                    // 处理跨年情况
                    if ($currentMonth > 12) {
                        $currentYear += floor(($currentMonth - 1) / 12);
                        $currentMonth = (($currentMonth - 1) % 12) + 1;
                    }

                    $data = [
                        'code' =>'时期'.($i+ 1) ,
                        'name' => $currentYear . '年' . sprintf('%02d', $currentMonth) . '月', // 修改：月份补零
                        'publicwelfare_id'=> $publicwelfare_id,
                        'community_id' => $community_id,
                        'status' => 1,
                        'create_time' => time()
                    ];

                    Db::name('fa_community_timezone_config')->insert($data);
                }
            }
        }

        $timeZoneData = Db::name('fa_community_timezone_config')
            ->field('id, code, name')
            ->select();
        // 修改结束

        $timeZones = [];
        foreach ($timeZoneData as $zone) {
            preg_match('/(\d+)年(\d+)月/', $zone['name'], $matches);
            $timeZones[$zone['code']] = [
                'year' => $matches[1] ?? date('Y'), // 如果没有年份，使用当前年份
                'month' => $matches[2] // 如果没有month，使用code作为月份
            ];
        }

        $list = [];
        $currentMonth = date('n');
        $currentYear = date('Y');

        // 生成时间段列表，并为每个时间段生成对应的时区数据
        foreach ($result as $key => $value) {
            $days = explode(',', $value['day']);
            foreach ($days as $k => $day) {
                // 为每个时区生成一个时间段条目
                foreach ($timeZones as $timeZoneCode => $timeZoneInfo) {
                    $list[] = array(
                        'id' => $value['code'],
                        'day' => intval($day),
                        'month' => $timeZoneInfo['month'],
                        'year' => $timeZoneInfo['year'],
                        'time_zone_code' => $timeZoneCode,
                        'startTime' => $value['start_time'],
                        'endTime' => $value['end_time'],
                        'text' => $day . "号 " . $value['start_time'] . "-" . $value['end_time'],
                        'originalText' => $value['start_time'] . "-" . $value['end_time'],
                    );
                }
            }
        }
        return $list;
    }

    /**
     * 获取时间段数据，使用整数ID作为键值
     */
    protected function getTimeSlotData($publicwelfare_id = 0)
    {
        // 从数据库直接获取时间段数据，确保使用整数ID
        $timeslots = Db::name('community_timeslot_config')
            ->where('status', 1)
            ->where('delete_time', null)
            ->field('id, code,name, day, start_time, end_time')
            ->select();

        $list = [];
        foreach ($timeslots as $timeslot) {
            // 如果 name 字段已经包含完整的显示名称，直接使用
            if (!empty($timeslot['name'])) {
                $list[$timeslot['code']] = $timeslot['name'];
            } else {
                // 否则组合日期和时间
                $startTime = date('H:i', strtotime($timeslot['start_time']));
                $endTime = date('H:i', strtotime($timeslot['end_time']));
                $list[$timeslot['code']] = $timeslot['day'] . '号 ' . $startTime . '-' . $endTime;
            }
        }

        // 如果没有数据，返回默认列表
        if (empty($list)) {
            $days = [20, 25, 30];
            $times = [
                '上午8:30-9:10',
                '上午9:20-10:10',
                '下午15:00-15:50'
            ];

            $list = [];
            $index = 1;
            foreach ($days as $day) {
                foreach ($times as $time) {
                    $list[$index] = $day . '号' . $time;
                    $index++;
                }
            }
        }

        return $list;
    }


    /**
     * 生成时间段键值
     */
    protected function generateTimeSlotKey($timeSlot, $communityId)
    {
        $timeSlotKey = $communityId . '_';
        if (is_array($timeSlot)) {
            $timeSlotKey .= $timeSlot['year'] . '_' .
                $timeSlot['month'] . '_' .
                $timeSlot['day'] . '_' .
                $timeSlot['startTime'] . '-' .
                $timeSlot['endTime'];
        } else {
            // 如果是字符串，假设格式为"Y-m-d H:i-H:i"
            $parts = explode(' ', $timeSlot);
            if (count($parts) >= 2) {
                $dateParts = explode('-', $parts[0]);
                $timeParts = explode('-', $parts[1]);

                if (count($dateParts) >= 3 && count($timeParts) >= 2) {
                    $timeSlotKey .= $dateParts[0] . '_' .  // year
                        $dateParts[1] . '_' .  // month
                        $dateParts[2] . '_' .  // day
                        $timeParts[0] . '-' .  // startTime
                        $timeParts[1];         // endTime
                }
            }
        }

        return $timeSlotKey;
    }

    /**
     * 获取指定时间段的可用课程
     */
    protected function getAvailableCoursesForTimeSlot($timeSlot, $communityId, $courseData, $courseTimeSlotUsed, $communityCoursesTaken)
    {
        // 构建时间标识符（不包含社区信息）
        $timeIdentifier = '';
        if (is_array($timeSlot)) {
            $timeIdentifier = $timeSlot['year'] . '_' .
                $timeSlot['month'] . '_' .
                $timeSlot['day'] . '_' .
                $timeSlot['startTime'] . '-' .
                $timeSlot['endTime'];
        } else {
            $parts = explode(' ', $timeSlot);
            if (count($parts) >= 2) {
                $timeIdentifier = $parts[0] . '_' . $parts[1]; // 日期_时间段
            }
        }

        // 获取该社区可用的课程
        $availableCourses = array_map(function ($id) use ($communityId, $courseData) {
            return [
                'id' => $id,
                'name' => $courseData[$id],
                'community_id' => $communityId // 假设所有课程都适用于当前社区
            ];
        }, array_keys($courseData));

        // 过滤掉已在同一时间安排的课程，不管哪个社区
        $availableCourses = array_filter($availableCourses, function ($course) use ($timeIdentifier, $courseTimeSlotUsed, $communityId, $communityCoursesTaken) {
            $courseTimeKey = $course['id'] . '_' . $timeIdentifier;

            // 检查该课程是否已经被安排在该时间段
            $timeSlotAvailable = !isset($courseTimeSlotUsed[$courseTimeKey]);

            // 检查社区是否已经上过这门课程
            $courseNotTakenByCommunity = !in_array($course['id'], $communityCoursesTaken[$communityId] ?? []);

            // 只有两个条件都满足才返回true
            return $timeSlotAvailable && $courseNotTakenByCommunity;
        });

        return $availableCourses;
    }

    /**
     * 导出排课表
     */
    public function export()
    {
        $month = $this->request->get('month', date('n'));
        $year = $this->request->get('year', date('Y'));
        $communityId = $this->request->get('community_id', 0);
        $projectId = $this->request->get('project_id', 0);
        $courseId = $this->request->get('course_id', 0);

        // 获取当前月份的排课数据
        $query = $this->model
            ->where('month', $month)
            ->where('year', $year)
            ->where('status', 1);

        if ($communityId > 0) {
            $query->where('community_id', $communityId);
        }

        if ($projectId > 0) {
            $query->where('project_id', $projectId);
        }

        if ($courseId > 0) {
            $query->where('course_id', $courseId);
        }

        $scheduleData = $query->select();

        // 整理数据为表格格式
        $tableData = [];
        foreach ($scheduleData as $schedule) {
            $key = $schedule['time_slot_id'] . '_' . $schedule['community_id'] . '_' . $schedule['time_zone_id'];
            $tableData[$key] = $schedule['course_id'];
        }

        $courseList = $this->model::getCourseList();
        $communityList = $this->model::getCommunityList();
        $timeZoneList = $this->model::getTimeZoneList();
        $timeSlotList = $this->model::getTimeSlotList();

        // 创建Excel文件
        $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
        $worksheet = $spreadsheet->getActiveSheet();

        // 设置表头
        $worksheet->setCellValue('A1', $year . '年' . $month . '月排课表');
        $worksheet->mergeCells('A1:' . chr(65 + count($timeZoneList)) . '1');

        // 设置时区表头
        $worksheet->setCellValue('A2', '时间段/社区');
        for ($i = 0; $i < count($timeZoneList); $i++) {
            $worksheet->setCellValue(chr(66 + $i) . '2', $timeZoneList[$i]); // 修改为直接使用$i而不是$i+1
        }

        // 填充数据
        $row = 3;
        foreach ($timeSlotList as $timeSlotId => $timeSlotName) {
            foreach ($communityList as $communityId => $communityName) {
                $worksheet->setCellValue('A' . $row, $timeSlotName . ' ' . $communityName);

                for ($i = 0; $i < count($timeZoneList); $i++) {
                    $timeZoneId = $i + 1;
                    $key = $timeSlotId . '_' . $communityId . '_' . $timeZoneId;
                    $courseId = isset($tableData[$key]) ? $tableData[$key] : '';
                    $courseName = $courseId ? $courseId . ':' . $courseList[$courseId] : '';
                    $worksheet->setCellValue(chr(66 + $i) . $row, $courseName);
                }

                $row++;
            }
        }

        // 输出Excel文件
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment;filename="排课表_' . $year . '年' . $month . '月.xlsx"');
        header('Cache-Control: max-age=0');

        $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
        $writer->save('php://output');
        exit;
    }

    /**
     * 添加排课
     */
    public function add()
    {
        if ($this->request->isPost()) {
            $params = $this->request->post("row/a");
            if ($params) {
                try {
                    // 数据验证
                    if (empty($params['course_id'])) {
                        $this->error('请选择课程');
                    }
                    if (empty($params['community_id'])) {
                        $this->error('请选择社区');
                    }
                    if (empty($params['time_zone_id'])) {
                        $this->error('请选择时区');
                    }
                    if (empty($params['time_slot_id'])) {
                        $this->error('请选择时间段');
                    }
                    if (empty($params['month'])) {
                        $this->error('请选择月份');
                    }
                    if (empty($params['year'])) {
                        $this->error('请输入年份');
                    }

                    // 检查是否存在重复排课
                    $exists = $this->model
                        ->where('course_id', $params['course_id'])
                        ->where('community_id', $params['community_id'])
                        ->where('time_zone_id', $params['time_zone_id'])
                        ->where('time_slot_id', $params['time_slot_id'])
                        ->where('month', $params['month'])
                        ->where('year', $params['year'])
                        ->where('status', 'normal')
                        ->find();

                    if ($exists) {
                        $this->error('该时间段已存在排课，请选择其他时间');
                    }

                    // 设置默认值
                    $params['create_time'] = date('Y-m-d H:i:s');
                    $params['update_time'] = date('Y-m-d H:i:s');
                    $params['status'] = isset($params['status']) ? $params['status'] : 'normal';
                    $params['weigh'] = isset($params['weigh']) ? intval($params['weigh']) : 0;

                    // 清理不需要的字段
                    unset($params['delete_time']);

                    // 保存数据
                    $result = $this->model->allowField(true)->save($params);
                    if ($result !== false) {
                        // 清除相关缓存
                        if (isset($params['publicwelfare_id'])) {
                            $this->clearCacheByPublicwelfareId($params['publicwelfare_id']);
                        }
                        $this->success('添加成功');
                    } else {
                        $this->error($this->model->getError() ?: '添加失败');
                    }
                } catch (\think\exception\PDOException $e) {
                    $this->error('数据库错误：' . $e->getMessage());
                } catch (\think\Exception $e) {
                    $this->error('系统错误：' . $e->getMessage());
                }
            }
            $this->error('参数不能为空');
        }

        // GET请求，显示添加表单
        return $this->view->fetch();
    }

    /**
     * 编辑排课
     */
    public function edit($ids = null)
    {
        $row = $this->model->get($ids);
        if (!$row) {
            $this->error('记录不存在');
        }

        if ($this->request->isPost()) {
            $params = $this->request->post("row/a");
            if ($params) {
                try {
                    // 数据验证
                    if (empty($params['course_id'])) {
                        $this->error('请选择课程');
                    }
                    if (empty($params['community_id'])) {
                        $this->error('请选择社区');
                    }
                    if (empty($params['time_zone_id'])) {
                        $this->error('请选择时区');
                    }
                    if (empty($params['time_slot_id'])) {
                        $this->error('请选择时间段');
                    }
                    if (empty($params['month'])) {
                        $this->error('请选择月份');
                    }
                    if (empty($params['year'])) {
                        $this->error('请输入年份');
                    }

                    // 检查是否存在重复排课（排除当前记录）
                    $exists = $this->model
                        ->where('course_code', $params['course_id'])
                        ->where('community_code', $params['community_id'])
                        ->where('time_zone_code', $params['time_zone_id'])
                        ->where('time_slot_code', $params['time_slot_id'])
                        ->where('month', $params['month'])
                        ->where('day', $params['day'])
                        ->where('year', $params['year'])
                        ->where('status', '1')
                        ->where('id', '<>', $ids)
                        ->find();

                    if ($exists) {
                        $this->error('该时间段已存在排课，请选择其他时间');
                    }

                    // 设置更新时间
                    $params['update_time'] = date('Y-m-d H:i:s');
                    $params['status'] = isset($params['status']) ? $params['status'] : '1';
                    $params['weigh'] = isset($params['weigh']) ? intval($params['weigh']) : 0;

                    // 清理不需要的字段
                    unset($params['delete_time']);
                    unset($params['create_time']);
                    $params['update_time'] = strtotime($params['update_time']);

                    // 更新数据
                    $result = $row->allowField(true)->save($params);
                    if ($result !== false) {
                        // 清除相关缓存
                        if (isset($params['publicwelfare_id'])) {
                            $this->clearCacheByPublicwelfareId($params['publicwelfare_id']);
                        } else {
                            // 如果没有publicwelfare_id参数，从原记录中获取
                            $this->clearCacheByPublicwelfareId($row['publicwelfare_id']);
                        }
                        $this->success('更新成功');
                    } else {
                        $this->error($row->getError() ?: '更新失败');
                    }
                } catch (\think\exception\PDOException $e) {
                    $this->error('数据库错误：' . $e->getMessage());
                } catch (\think\Exception $e) {
                    $this->error('系统错误：' . $e->getMessage());
                }
            }
            $this->error('参数不能为空');
        }
        $row['course_id'] = db("fa_community_course_config")->where('code', $row['course_code'])->where("publicwelfare_id", $row['publicwelfare_id'])->value('id');
        $row['community_id'] = db("fa_community_code_config")->where('code', $row['community_code'])->where("publicwelfare_id", $row['publicwelfare_id'])->value('id');
        $row['time_zone_id'] = db("fa_community_timezone_config")->where('code', $row['time_zone_code'])->where("publicwelfare_id", $row['publicwelfare_id'])->value('id');
        $row['time_slot_id'] = db("fa_community_timeslot_config")->where('code', $row['time_slot_code'])->where("publicwelfare_id", $row['publicwelfare_id'])->value('id');
        // GET请求，显示编辑表单
        $this->view->assign("row", $row);
        return $this->view->fetch();
    }

    /**
     * 清空项目排期
     */
    public function clear()
    {
        $publicwelfare_id = $this->request->post('publicwelfare_id', 0);

        if (!$publicwelfare_id) {
            $this->error('请选择要清空排期的项目');
        }

        Db::startTrans();
        try {
            // 物理删除指定项目的排期记录
            $result = $this->model
                ->where('publicwelfare_id', $publicwelfare_id)->delete();

            if ($result === false) {
                throw new Exception('删除操作失败');
            }
            db::name('fa_course_table_autoplan_temp')->where('publicwelfare_id', $publicwelfare_id)->delete();
            //db::name('eb_classes')->where('publicwelfare_id', $publicwelfare_id)->delete();

            // 清除相关缓存
            $this->clearCacheByPublicwelfareId($publicwelfare_id);

            Db::commit();
            $this->success('清空项目排期成功');
        } catch (Exception $e) {
            Db::rollback();
            $this->error($e->getMessage());
        }
    }

    /**
     * 删除排课记录（物理删除）
     */
    public function del($ids = null)
    {
        if (!$this->request->isPost()) {
            $this->error('非法请求');
        }

        $ids = $ids ? $ids : $this->request->post("ids");
        if (empty($ids)) {
            $this->error('参数不能为空');
        }

        $pk = $this->model->getPk();
        $adminIds = $this->getDataLimitAdminIds();
        if (is_array($adminIds)) {
            $this->model->where($this->dataLimitField, 'in', $adminIds);
        }

        $list = $this->model->where($pk, 'in', $ids)->select();
        if (!$list) {
            $this->error('记录不存在');
        }

        Db::startTrans();
        try {
            // 获取要删除的记录信息，用于清除缓存
            $deletedRecords = $this->model->where($pk, 'in', $ids)->select();
            $publicwelfareIds = [];
            foreach ($deletedRecords as $record) {
                if (!in_array($record['publicwelfare_id'], $publicwelfareIds)) {
                    $publicwelfareIds[] = $record['publicwelfare_id'];
                }
            }

            // 执行物理删除
            $count = $this->model->where($pk, 'in', $ids)->delete();

            if ($count === false) {
                throw new Exception('删除操作失败');
            }

            // 清除相关缓存
            foreach ($publicwelfareIds as $publicwelfareId) {
                $this->clearCacheByPublicwelfareId($publicwelfareId);
            }

            Db::commit();
            $this->success('删除成功', null, ['deleted_count' => $count, 'skip_cache' => 1]);
        } catch (Exception $e) {
            Db::rollback();
            $this->error('删除失败：' . $e->getMessage());
        }
    }

    /**
     * 正式排课 - 将Autoplantemp数据导入到正式表
     */
    public function confirmSchedule()
    {
        if (!$this->request->isPost()) {
            $this->error('非法请求');
        }

        $publicwelfare_id = $this->request->post('publicwelfare_id', 0);

        if (!$publicwelfare_id) {
            $this->error('请选择要正式排课的项目');
        }

        Db::startTrans();
        try {
            // 检查是否已存在正式排课记录
            $existCount = Db::name('fa_course_table_autoplan')
                ->where('publicwelfare_id', $publicwelfare_id)
                ->count();

            if ($existCount > 0) {
                $this->error('该项目已存在正式排课记录，无法重复导入');
            }

            // 获取Autoplantemp中该项目的所有记录
            $tempRecords = Db::name('fa_course_table_autoplan_temp')
                ->where('publicwelfare_id', $publicwelfare_id)
                ->select();

            if (empty($tempRecords)) {
                $this->error('该项目暂无排课记录可导入');
            }

            // 准备插入正式表的数据
            $formalData = [];
            foreach ($tempRecords as $record) {
                // 移除临时表特有字段，保留正式表需要的字段
                unset($record['id']); // 移除主键，让正式表自动生成
                $record['create_time'] = time();
                $record['update_time'] = time();
                $formalData[] = $record;
            }

            // 使用insertUpdate方法导入到正式表
            $result = Db::name('fa_course_table_autoplan')->insertAll($formalData);

            if ($result === false) {
                throw new Exception('导入正式排课表失败');
            }

            Db::commit();
            $this->success('正式排课成功，共导入 ' . count($formalData) . ' 条记录');

        } catch (Exception $e) {
            Db::rollback();
            $this->error('正式排课失败：' . $e->getMessage());
        }
    }

    /**
     * 检查项目是否已有正式排课记录
     */
    public function checkFormalSchedule()
    {
        $publicwelfare_id = $this->request->param('publicwelfare_id', 0);

        if (!$publicwelfare_id) {
            return json(['code' => 0, 'msg' => '参数错误']);
        }

        $count = Db::name('fa_course_table_autoplan')
            ->where('publicwelfare_id', $publicwelfare_id)
            ->count();

        return json([
            'code' => 1,
            'data' => ['has_formal' => $count > 0],
            'msg' => '查询成功'
        ]);
    }

    /**
     * 统一的重复检查逻辑
     */
    private function checkDuplicateSchedule($params, $excludeId = null)
    {
        $query = $this->model
            ->where('course_code', $params['course_code'])
            ->where('community_code', $params['community_code'])
            ->where('time_zone_code', $params['time_zone_code'])
            ->where('time_slot_code', $params['time_slot_code'])
            ->where('year', $params['year'])
            ->where('month', $params['month'])
            ->where('day', $params['day'])
            ->where('status', 1);

        if ($excludeId) {
            $query->where('id', '<>', $excludeId);
        }

        return $query->find();
    }

    /**
     * 根据ocation_id获取社区id
     * 复制自Community控制器的findCommunityId方法
     */
    private function findCommunityId($ocation_id)
    {
        // 先直接查询
        $community_id = Db::name('eb_school_community')
            ->where('ocation_id', $ocation_id)
            ->value('community_id');

        if ($community_id) {
            return $community_id;
        }

        // 如果没有直接记录，通过父级教学点递归查找
        return $this->findCommunityIdRecursive($ocation_id);
    }

    /**
     * 递归查找父级教学点的community_id
     */
    private function findCommunityIdRecursive($ocation_id, $depth = 0)
    {
        // 防止无限递归，最多查找5层
        if ($depth > 8 || empty($ocation_id)) {
            return null;
        }

        // 查询当前教学点的父级ID
        $parent_id = Db::name('fa_ocation')
            ->where('id', $ocation_id)
            ->value('pid');

        if (!$parent_id) {
            return null;
        }

        // 查询父级教学点是否有对应的社区ID
        $community_id = Db::name('eb_school_community')
            ->where('ocation_id', $parent_id)
            ->value('community_id');

        if ($community_id) {
            return $community_id;
        }

        // 如果父级也没有，继续向上查找
        return $this->findCommunityIdRecursive($parent_id, $depth + 1);
    }

    /**
     * 取消正式排课
     */
    public function cancelSchedule()
    {
        if (!$this->request->isPost()) {
            return json([
                'code' => 0,
                'msg' => '非法请求方式',
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }

        $publicwelfare_id = $this->request->post('publicwelfare_id', 0);
        $password = $this->request->post('password', '');

        if (!$publicwelfare_id) {
            \think\Log::record('cancelSchedule失败：项目ID为空', 'error');
            return json([
                'code' => 0,
                'msg' => '项目ID不能为空',
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }

        // 验证密码
        if (!$this->validateSchedulePassword($password)) {
            \think\Log::record('cancelSchedule失败：密码验证失败 publicwelfare_id=' . $publicwelfare_id, 'error');
            return json([
                'code' => 0,
                'msg' => '密码错误，无法执行取消正式排课操作',
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }

        // 记录操作开始
        $userId = 0;
        try {
            $user = $this->auth->getUserInfo();
            $userId = is_array($user) && isset($user['id']) && is_scalar($user['id']) ? $user['id'] : 0;
        } catch (\Exception $e) {
            $userId = 0;
        }

        \think\Log::record('开始取消正式排课 publicwelfare_id=' . $publicwelfare_id . ' user_id=' . $userId, 'info');

        // 开始事务
        Db::startTrans();
        try {
            // 检查项目是否存在
            $project = Db::name('fa_community_publicwelfare')
                ->where('id', $publicwelfare_id)
                ->find();

            if (!$project) {
                Db::rollback();
                \think\Log::record('cancelSchedule失败：项目不存在 publicwelfare_id=' . $publicwelfare_id, 'error');
                return json([
                    'code' => 0,
                    'msg' => '指定的项目不存在',
                    'data' => null,
                    'url' => null,
                    'wait' => 3
                ]);
            }

            // 检查正式表中是否有数据
            $formalCount = Db::name('course_table_autoplan')
                ->where('publicwelfare_id', $publicwelfare_id)
                ->count();

            if ($formalCount == 0) {
                Db::rollback();
                \think\Log::record('cancelSchedule失败：正式表无数据 publicwelfare_id=' . $publicwelfare_id, 'error');
                return json([
                    'code' => 0,
                    'msg' => '该项目没有正式排课数据，无需取消',
                    'data' => null,
                    'url' => null,
                    'wait' => 3
                ]);
            }

            \think\Log::record('找到正式排课数据 publicwelfare_id=' . $publicwelfare_id . ' count=' . $formalCount, 'info');

            // 删除正式表中的数据
            \think\Log::record('开始删除正式排课数据 publicwelfare_id=' . $publicwelfare_id, 'info');

            $deleteResult = Db::name('course_table_autoplan')
                ->where('publicwelfare_id', $publicwelfare_id)
                ->delete();

            if ($deleteResult === false) {
                throw new \Exception('删除正式排课数据失败');
            }

            \think\Log::record('删除正式排课数据成功 publicwelfare_id=' . $publicwelfare_id . ' deleted_count=' . $deleteResult, 'info');

            // 提交事务
            Db::commit();

            // 记录成功日志
            \think\Log::record('取消正式排课成功 publicwelfare_id=' . $publicwelfare_id . ' deleted_count=' . $deleteResult . ' user_id=' . $userId, 'info');

            $message = '取消正式排课成功，共删除 ' . $deleteResult . ' 条记录';
            return json([
                'code' => 1,
                'msg' => $message,
                'data' => [
                    'publicwelfare_id' => $publicwelfare_id,
                    'deleted_count' => $deleteResult,
                    'project_name' => $project['project_name'] ?? ''
                ],
                'url' => null,
                'wait' => 3
            ]);

        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();

            // 记录详细错误日志
            \think\Log::record('取消正式排课失败 publicwelfare_id=' . $publicwelfare_id . ' error=' . $e->getMessage() . ' user_id=' . $userId, 'error');

            return json([
                'code' => 0,
                'msg' => '取消正式排课失败：' . $e->getMessage(),
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }
    }

    /**
     * 验证正式排课密码
     * @param string $password 用户输入的密码
     * @return bool
     */
    private function validateSchedulePassword($password)
    {
        // 设置正式排课密码（可以从配置文件或数据库读取）
        $correctPassword = config('schedule_password') ?: '1594561';

        // 临时调试日志 - 记录密码验证详情
        \think\Log::record('密码验证调试 - 输入密码: [' . $password . '] 长度: ' . strlen($password) . ' 正确密码: [' . $correctPassword . '] 长度: ' . strlen($correctPassword), 'info');
        \think\Log::record('密码验证调试 - 输入密码十六进制: ' . bin2hex($password) . ' 正确密码十六进制: ' . bin2hex($correctPassword), 'info');

        $result = $password === $correctPassword;
        \think\Log::record('密码验证调试 - 验证结果: ' . ($result ? '通过' : '失败'), 'info');

        return $result;
    }
}
